import tkinter as tk
from datetime import time, datetime
from tkinter import scrolledtext, messagebox, ttk
from conn_serial import ConnSerial
from signal_buffer import SignalBuffer
import serial.tools.list_ports


class GUI:
    def __init__(self, master):
        self.master = master
        self.master.title("串口通讯工具")

        self.signal_buffer = SignalBuffer()
        self.serial_conn = None

        # 创建一个框架用于状态指示器和状态文本
        status_frame = tk.Frame(master)
        status_frame.pack(side=tk.TOP, anchor=tk.NW, padx=5, pady=5)

        # 创建状态指示器
        self.status_canvas = tk.Canvas(status_frame, width=20, height=20)
        self.status_canvas.pack(side=tk.LEFT)

        # 创建状态文本标签
        self.status_label = tk.Label(status_frame, text="未连接", fg="red")
        self.status_label.pack(side=tk.LEFT)

        self.update_status_indicator(False)  # 初始状态为未连接

        # 创建作者文本标签
        self.Author_label = tk.Label(master, text="Author: Carl", fg="Black")
        self.Author_label.pack(side=tk.TOP, anchor=tk.NW, padx=5)

        self.create_serial_config_frame()

        # 创建输出文本框和滚动条
        self.output_textbox = tk.Text(master, wrap=tk.WORD)
        self.output_textbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        self.scrollbar = tk.Scrollbar(master, command=self.output_textbox.yview)
        self.scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        self.output_textbox.config(yscrollcommand=self.scrollbar.set)

        # 绑定滚动事件
        self.output_textbox.bind('<ButtonRelease-1>', self.on_scroll)
        self.output_textbox.bind('<MouseWheel>', self.on_scroll)

        self.connect_button = tk.Button(master, text="连接串口", command=self.connect_serial)
        self.connect_button.pack(pady=10)

        self.close_button = tk.Button(master, text="关闭串口", command=self.close_serial)
        self.close_button.pack(pady=10)

        self.update_ports()
        self.check_ports()
        self.master.after(100, self.read_from_buffer)

        # 创建解码选择框
        tk.Label(master, text="输出解码:").pack(side=tk.TOP, anchor=tk.NW, padx=5)
        self.output_decode_var = tk.StringVar(value="ASCII")
        self.output_decode_combobox = ttk.Combobox(master, textvariable=self.output_decode_var, values=["ASCII", "HEX"])
        self.output_decode_combobox.pack(side=tk.TOP, anchor=tk.NW, padx=5)

        # 创建输出字符串输入框
        tk.Label(master, text="输出字符串:").pack(side=tk.TOP, anchor=tk.NW, padx=5)
        self.output_string_entry = tk.Entry(master)
        self.output_string_entry.pack(side=tk.TOP, anchor=tk.NW, padx=5)
        self.auto_scroll = True  # 添加一个标志来控制自动滚动

    def on_scroll(self, event):
        self.auto_scroll = self.output_textbox.yview()[1] == 1.0  # 检查是否在底部

    def create_serial_config_frame(self):
        frame = tk.Frame(self.master)
        frame.pack(pady=10)

        tk.Label(frame, text="选择串口:").grid(row=0, column=0)
        self.port_var = tk.StringVar()
        self.port_combobox = ttk.Combobox(frame, textvariable=self.port_var)
        self.port_combobox.grid(row=0, column=1)

        tk.Label(frame, text="波特率:").grid(row=1, column=0)
        self.baudrate_var = tk.StringVar(value="115200")
        self.baudrate_combobox = ttk.Combobox(frame, textvariable=self.baudrate_var,
                                              values=["9600", "14400", "19200", "38400", "57600",
                                                      "115200", "500000", "916200"])
        self.baudrate_combobox.grid(row=1, column=1)

        tk.Label(frame, text="数据位:").grid(row=2, column=0)
        self.bytesize_var = tk.StringVar(value="8")
        self.bytesize_combobox = ttk.Combobox(frame, textvariable=self.bytesize_var,
                                              values=["5", "6", "7", "8"])
        self.bytesize_combobox.grid(row=2, column=1)

        tk.Label(frame, text="奇偶校验:").grid(row=3, column=0)
        self.parity_var = tk.StringVar(value="N")
        self.parity_combobox = ttk.Combobox(frame, textvariable=self.parity_var,
                                            values=["N", "E", "O"])
        self.parity_combobox.grid(row=3, column=1)

        tk.Label(frame, text="停止位:").grid(row=4, column=0)
        self.stopbits_var = tk.StringVar(value="1")
        self.stopbits_combobox = ttk.Combobox(frame, textvariable=self.stopbits_var,
                                              values=["1", "1.5", "2"])
        self.stopbits_combobox.grid(row=4, column=1)

        self.xonxoff_var = tk.BooleanVar(value=False)
        tk.Checkbutton(frame, text="XON/XOFF", variable=self.xonxoff_var).grid(row=5, column=0, columnspan=2)

        # 添加相关的复选框和颜色选择器：
        tk.Label(frame, text="接收解码为：").grid(row=6, column=0)
        self.receive_mode_var = tk.StringVar(value="ASCII")
        self.receive_mode_combobox = ttk.Combobox(frame, textvariable=self.receive_mode_var, values=["ASCII", "HEX"])
        self.receive_mode_combobox.grid(row=6, column=1)

        self.timestamp_var = tk.BooleanVar(value=False)
        tk.Checkbutton(frame, text="显示时间戳", variable=self.timestamp_var).grid(row=6, column=2)

        # self.bg_color_var = tk.StringVar(value="white")
        # self.font_color_var = tk.StringVar(value="black")
        # # 添加颜色选择器（可以使用颜色选择对话框）
        # TODO 这里可能需要重写一下 换一个方法进行绑定事件,现在是单独手动输入或者下拉菜单各自绑定一个事件
        # 绑定事件
        self.baudrate_combobox.bind("<<ComboboxSelected>>", self.on_config_change)
        self.bytesize_combobox.bind("<<ComboboxSelected>>", self.on_config_change)
        self.parity_combobox.bind("<<ComboboxSelected>>", self.on_config_change)
        self.stopbits_combobox.bind("<<ComboboxSelected>>", self.on_config_change)
        self.xonxoff_var.trace_add("write", self.on_config_change)

        # 绑定手动输入事件
        self.baudrate_combobox.bind("<KeyRelease>", self.on_config_change)  # 绑定手动输入事件

    def update_status_indicator(self, is_connected):
        """更新状态指示器的颜色和状态文本"""
        self.status_canvas.delete("all")  # 清除之前的绘图
        color = "green" if is_connected else "red"
        self.status_canvas.create_oval(5, 5, 15, 15, fill=color, outline=color)
        self.status_label.config(text="已连接" if is_connected else "未连接", fg=color)  # 更新状态文本

    def on_config_change(self, *args):
        if self.serial_conn and self.serial_conn.is_open:
            self.close_serial()  # 关闭当前连接
            self.connect_serial()  # 重新连接

    def update_ports(self):
        ports = serial.tools.list_ports.comports()
        port_list = [port.device for port in ports]
        self.port_combobox['values'] = port_list
        if port_list:
            if self.port_var.get() not in port_list:
                self.port_var.set(port_list[0])

    def check_ports(self):
        self.update_ports()
        self.master.after(500, self.check_ports)

    def connect_serial(self):
        if not self.serial_conn:
            try:
                self.serial_conn = ConnSerial(
                    port=self.port_var.get(),
                    baud_rate=int(self.baudrate_var.get()),
                    byte_size=int(self.bytesize_var.get()),
                    parity=self.parity_var.get(),
                    stop_bits=float(self.stopbits_var.get()),
                    xon_xoff=self.xonxoff_var.get(),
                    signal_buffer=self.signal_buffer
                )
                self.update_status_indicator(True)  # 更新状态为连接成功
                # messagebox.showinfo("信息", "串口连接成功！")
            except Exception as e:
                print(e)
                messagebox.showerror("错误", "连接串口失败: {e}")

    def close_serial(self):
        if self.serial_conn:
            self.serial_conn.close()
            self.serial_conn = None
            self.update_status_indicator(False)  # 更新状态为未连接
            # messagebox.showinfo("信息", "串口已关闭")

    # 在插入数据后，检查用户是否手动滚动
    def read_from_buffer(self):
        try:
            if self.serial_conn and self.serial_conn.is_open:
                while not self.signal_buffer.is_empty():
                    data = self.signal_buffer.get()
                    if data:
                        decoded_data = self.signal_buffer.decode(data, self.output_decode_var.get())
                        timestamp = f"[{datetime.now().strftime('%H:%M:%S')}] " if self.timestamp_var.get() else ""
                        self.output_textbox.insert(tk.END, f"{timestamp}{decoded_data}\n")

                        # 只有在 auto_scroll 为 True 时才自动滚动
                        if self.auto_scroll:
                            self.output_textbox.see(tk.END)

        except Exception as e:
            print(f"读取缓冲区时出错: {e}")
            self.close_serial()

        self.master.after(100, self.read_from_buffer)


# 启动应用
if __name__ == "__main__":
    root = tk.Tk()
    gui = GUI(root)
    root.mainloop()
